
#include "ui_widget.h"
#include "ui_manager.h"
#include "ui_timeline.h"

#include "ui_slider.h"
#include "ui_dropdown.h"
#include "ui_multiline.h"
#include "ui_progress.h"
#include "ui_checkbox.h"
#include "ui_flashwidget.h"
//#include "ui_partwidget.h"
#include "ui_part2dwidget.h"
#include "ui_mover.h"
#include "ui_moviewidget.h"
#include "ui_skin.h"
#include "ui_listwidget.h"
#include "ui_bipedwidget.h"
#include "ui_dragwidget.h"
#include "ui_graph.h"
#include "ui_polyline.h"
#include "ui_calendar.h"

#include "graphics/graphics.h"
#include "graphics/graphics_util.h"

// audio
#include "audio/audio.h"

#include "lang/lang.h"

#include "script/scripthelper.h"
#include "script/write_lua.h"
#include "console/console.h"

#include "font/font_manager.h"

#include <algorithm>
#include <cassert>

#include "util/timer.h"		    // Needs to come in early
#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging
#ifdef _ENABLE_LUABIND
#include <luabind/luabind.hpp>
#include <luabind/copy_policy.hpp>
#endif //_ENABLE_LUABIND
#include <algorithm>

using namespace ui;
using namespace script;

void	UIWidget::SetWidgetText(ui::UIWidget* pWidget, const char*  _Msg, ...)
{
	if (pWidget)
	{
		// Concatanate the message into a single buffer
		char Message[1024];
		va_list ArgP;
		va_start(ArgP, _Msg);
		vsprintf(Message, _Msg, ArgP);
		va_end(ArgP);

		pWidget->SetTextA(Message);
	}
}


UIWidget::UIWidget(UIWidget*			pParent, const std::string& Name) :
	num::NamedList<UIWidget*>(),
	m_CurrentState(WS_MOUSE_OFF),
	m_IsActive(true),
	m_IsVisible(true),
	m_IsHoovering(false), 
	m_Scale(1.0f),
	m_Rotation(0.0f),
	m_pParent(pParent),
	m_CanDrag(false),
	m_Name(Name),
	m_pManager(NULL),
	m_MouseOverEvent(false),
	m_MouseOffEvent(false),
	m_BlockAllEvents(false),
	m_PlaySound(true),
	m_Color(0xFFFFFFFF),
	m_DisableOverSound(false),
	m_DisableClickSound(false),
	m_IsPassword(false),
	m_pSkin(NULL),
	m_OverMode(WO_NONE),
	m_UseMask(false),
	m_IsMouseDownHere(false),
	m_IsRenderRotated(false),
	m_IsImagedLoaded(false)
{
	m_Type = WT_WIDGET;
	m_Text.SetOwner(this);
	m_pManager = &ui::UIManager::Instance();

	for (int i=0; i<WE_COUNT; i++)	m_EventDg[i] = 0;
}	

UIWidget::~UIWidget()
{
	ClearSet();
	//ClearMovers();
	DeleteMovers();
	UTIL_SAFE_DELETE(m_pSkin);
}

void		UIWidget::FlushSprites()
{
	for (unsigned int i=0; i<WI_COUNT; i++)
		m_ImageA[i].FlushImage();	
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
			It->second->FlushSprites();
	}
}


void		UIWidget::ClearMovers()
{
	for (unsigned int i=0; i<m_MoverList.size(); i++)
	{
		//delete m_MoverList[i];
		m_MoverList[i]->Invalidate();
	}
}

void		UIWidget::DeleteMovers()
{
	for (unsigned int i=0; i<m_MoverList.size(); i++)
	{
		delete m_MoverList[i];
	}
	m_MoverList.resize(0);
}

bool		UIWidget::Create(const std::string& Name, const math::Vec2& Pos, const math::Vec2& Size)
{
	// what needs to be reset here?
	SetPosition(Pos);
	SetSize(Size);
	m_BaseUV1	= math::Vec2(0.0f, 0.0f);
	m_BaseUV2	= math::Vec2(1.0f, 1.0f);
	SetColor(1, 1, 1, 1);
	SetRotation(0);
    m_Name = Name;
	m_Text.SetFont(ui::UIManager::Instance().GetDefaultFont());
	SetTextW(L"");
	m_IsActive = true;
	for (int i=0; i<WS_COUNT; i++)
	{
		m_ImageA[i].m_UV1 = m_BaseUV1;
		m_ImageA[i].m_UV2 = m_BaseUV2;
	}
	m_ScriptFile = "unknown";
	return true;
}

void				UIWidget::SetAdditive(bool b)
{
	for (int i=0; i<WI_COUNT; i++)
	{
		m_ImageA[i].m_Additive = b;
	}
}
bool				UIWidget::IsAdditive()
{
	for (int i=0; i<WI_COUNT; i++)
	{
		if (m_ImageA[i].IsValid())
			return m_ImageA[i].m_Additive;
	}
	return false;
}

bool				UIWidget::Load(LuaPlus::LuaObject& _LObj)
{
    assert(_LObj.IsTable() && "Can only load a widget from a table object!");

	// load the graphics:
	SetPosition(ScriptHelper::GetTableVec2(_LObj, "Pos", math::Vec2(0, 0)));
	m_BaseUV1	= ScriptHelper::GetTableVec2(_LObj, "UV1", math::Vec2(0.0f, 0.0f));
	m_BaseUV2	= ScriptHelper::GetTableVec2(_LObj, "UV2", math::Vec2(1.0f, 1.0f));
	
	m_PlaySound = ScriptHelper::GetTableBool(_LObj, "PlaySoundEvent", true);
	m_DisableOverSound	= ScriptHelper::GetTableBool(_LObj, "DisableOverSound", false);
	m_DisableClickSound	= ScriptHelper::GetTableBool(_LObj, "DisableClickSound", false);


	m_NextWidget		= ScriptHelper::GetTableString(_LObj, "Next", "");
	m_IsPassword		= ScriptHelper::GetTableBool(_LObj, "IsPassword", false);
	SetPassword(m_IsPassword);
	m_BlockAllEvents = ScriptHelper::GetTableBool(_LObj, "BlockAll", false);
	math::Vec4 Col  = ScriptHelper::GetTableVec4(_LObj, "Color", math::Vec4(1, 1, 1, 1));
	math::Vec4 TextCol  = ScriptHelper::GetTableVec4(_LObj, "TextColor", math::Vec4(1, 1, 1, 1));
	SetColor(Col.x, Col.y, Col.z, Col.w);
	SetRotation(ScriptHelper::GetTableFloat(_LObj, "Rotation", 0));
	m_IsRenderRotated = ScriptHelper::GetTableBool(_LObj, "IsRenderRotated", false);

	std::string	SkinElement = ScriptHelper::GetTableString(_LObj, "SkinElement", "");
	if (!SkinElement.empty())
	{
		SetSkin(SkinElement);
	}

	// read mask flag before any image loading occurs
	m_UseMask			= ScriptHelper::GetTableBool(_LObj, "UseMask", false);

	m_IsRenderRotated   = ScriptHelper::GetTableBool(_LObj, "IsRenderRotated", false);

	// load files
	std::string		ImageFile[WS_COUNT];
	ImageFile[WS_MOUSE_OVER]	= ScriptHelper::GetTableString(_LObj, "MouseOver", "");
	ImageFile[WS_MOUSE_OFF]		= ScriptHelper::GetTableString(_LObj, "MouseOff", "");
	ImageFile[WS_MOUSE_CLICK]	= ScriptHelper::GetTableString(_LObj, "MouseClick", "");

	unsigned int i=0;
	for ( i=0; i<WS_COUNT; i++)
	{
		if (!ImageFile[i].empty())
		{
			m_ImageA[i].Create(	ImageFile[i], m_BaseUV1, m_BaseUV2, false);
			if (m_UseMask)
				m_ImageA[i].CreateMask();

			m_ImageA[i].GetScreenSize(m_ImageA[i].m_Size);
		}
	}

	// update the size
	m_Size = ScriptHelper::GetTableVec2(_LObj, "Size");
	if (m_pSkin)
	{
		m_Size = m_pSkin->AdjustSize(m_Size);
	}
	if (m_Size.Magnitude() < 0.0001f)
	{
		//empty size.. pull it from image
		if (m_ImageA[WS_MOUSE_OFF].IsValid())
		{
			m_Size = m_ImageA[WS_MOUSE_OFF].m_Size;
		} else
		{
			m_Size = math::Vec2(0.3f, 0.3f);
		}
	}
	SetSize(m_Size);

	// text stuff
    m_Name = ScriptHelper::GetTableString(_LObj, "Name", "");
	if (m_Name.empty())
	{
		static	unsigned int NoNameCount = 1;
		char	Buffer[256];
		sprintf(Buffer, "Noname_widget%i", NoNameCount);
		m_Name = Buffer;
		NoNameCount++;
	}
	m_Text.SetFont(ScriptHelper::GetTableString(_LObj, "Font", ui::UIManager::Instance().GetDefaultFont()));
	m_Text.SetBorder(ScriptHelper::GetTableVec2(_LObj, "BorderSize", math::Vec2(0.005f, 0.005f)));
	// register itself with the root ?
	std::string	HJust = ScriptHelper::GetTableString(_LObj, "HJust", "");
	std::string	VJust = ScriptHelper::GetTableString(_LObj, "VJust", "");
	int		MaxInput = ScriptHelper::GetTableInt(_LObj, "MaxInput", 0);
	bool	CanEdit	 = ScriptHelper::GetTableBool(_LObj, "CanEdit", false);
	bool	EditMultiline = ScriptHelper::GetTableBool(_LObj, "CanEditMultiline", false);
	SetTextColor(TextCol.x, TextCol.y, TextCol.z, TextCol.w);

	if (!HJust.empty())
		m_Text.SetHorizJust(HJust);
	if (!VJust.empty())
		m_Text.SetVertJust(VJust);

	if (MaxInput > 0)
		m_Text.SetMaxInputLen(MaxInput);

	m_Text.SetCanEdit(CanEdit);
	m_Text.SetCanEditMultiline(EditMultiline);
	SetTextA(ScriptHelper::GetTableString(_LObj, "Text", ""));
	SetUnderline(ScriptHelper::GetTableBool(_LObj, "Underline", false));


	SetAdditive(ScriptHelper::GetTableBool(_LObj, "Additive", false));

	for (i=0; i<WE_COUNT; i++)
	{
		std::string Event	= GetStringFromEvent((WIDGET_EVENT)i);
		LuaPlus::LuaObject	EventObj = _LObj.GetByName(Event.c_str());
		if (EventObj.IsString())
		{
			SetEvent((WIDGET_EVENT)i, EventObj.GetString());
		}
	}

	const char*	Name = m_Name.c_str();
	// load children
	LuaPlus::LuaObject	Children = _LObj.GetByName("Children");
	if (Children.IsTable())
	{
		for (i = 0; i<(unsigned int)Children.GetCount(); i++)
		{
			UIWidget*	pWidget = UIManager::CreateWidget(this, Children.GetByIndex(i+1));
			if (pWidget)
			{
				AddChild(pWidget);
			} else
			{
				_LOG(MSG_WARNING, "Unable to create child!");
			}
		}
	}

	if (ScriptHelper::GetTableInt(_LObj, "CanDrag", 0) != 0)
		m_CanDrag = true;

	if (ScriptHelper::GetTableInt(_LObj, "Active", 1) != 1)
		m_IsActive = false;

	//tip
	m_HooverTip = ScriptHelper::GetTableString(_LObj, "Tip", ""); 

	TriggerEvent(WE_ON_LOAD);
	return true;
}

void		UIWidget::PostLoad()
{
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		It->second->PostLoad();
	}	
	// setup the reverse as well
	if (!m_NextWidget.empty())
	{
		ui::UIWidget*	pWidget = GetPanel()->GetWidgetByName(m_NextWidget);
		if (pWidget)
		{
			pWidget->m_PrevWidget = m_Name;	
		}
	}
}


UIWidget*	UIWidget::GetClone()
{
	UIWidget* pNew = new UIWidget(m_pParent, GetCloneName(m_Name));
	FillCloneInfo(pNew);
	return pNew;
}

std::string			UIWidget::GetCloneName(const std::string& Name)
{
	static  int Count=0;
	char	Buffer[256];
	sprintf(Buffer, "Clone_%i", Count++);
	return Buffer;
}

void				UIWidget::FillCloneInfo(UIWidget* pWidget)
{
	pWidget->m_pManager			= this->m_pManager;
	pWidget->m_pParent			= this->m_pParent;
	pWidget->m_CurrentState		= this->m_CurrentState;
	pWidget->m_Text				= this->m_Text;
	pWidget->m_Type				= this->m_Type;

//	pWidget->m_Name				= this->m_Name;
	pWidget->m_HooverTip		= this->m_HooverTip;
	pWidget->m_ScriptFile		= this->m_ScriptFile;
	pWidget->m_IsHoovering		= this->m_IsHoovering;
	pWidget->m_IsActive			= this->m_IsActive;
	pWidget->m_CanDrag			= this->m_CanDrag;

	pWidget->m_Pos				= this->m_Pos;
	pWidget->m_Size				= this->m_Size;
	pWidget->m_BaseUV1			= this->m_BaseUV1;
	pWidget->m_BaseUV2			= this->m_BaseUV2;
	pWidget->m_Rotation			= this->m_Rotation;
	pWidget->m_Scale			= this->m_Scale;
	pWidget->m_Color			= this->m_Color;
	pWidget->SetAdditive(this->IsAdditive());
	pWidget->m_MouseOverEvent	= this->m_MouseOverEvent;
	pWidget->m_MouseOffEvent	= this->m_MouseOffEvent;
	pWidget->m_BlockAllEvents	= this->m_BlockAllEvents;
	pWidget->SetUnderline(this->GetUnderline());

	pWidget->m_NextWidget		= this->m_NextWidget;
	pWidget->SetCanEdit(this->m_Text.IsEditable());
	pWidget->SetCanEditMultiline(this->m_Text.CanEditMultiline());
	pWidget->m_Text.SetMaxInputLen(this->m_Text.GetMaxInputLen());
	pWidget->SetPassword(this->m_IsPassword);

	// mask
	pWidget->m_UseMask			= this->m_UseMask;

	pWidget->m_IsRenderRotated  = this->m_IsRenderRotated;

	/// state info
	for (int i=0; i<WI_COUNT; i++)
	{
		pWidget->m_ImageA[i].Create(
			this->m_ImageA[i].GetFilename(),
			this->m_ImageA[i].GetUV1(),
			this->m_ImageA[i].GetUV2(),
			this->m_ImageA[i].IsAdditive());

		if (pWidget->m_UseMask)
			pWidget->m_ImageA[i].CreateMask();
	}
	for (int i=0; i<WE_COUNT; i++)
	{
		pWidget->m_EventA[i] = this->m_EventA[i];
		pWidget->m_EventDg[i] = this->m_EventDg[i];
	}

	if (m_pSkin)
	{
		pWidget->SetSkin(m_pSkin->Name);
	}

}

bool		UIWidget::ExportToFile(script::WriteLua*	pWL)
{
	assert(pWL);

	// now to export all available data
	// text stuff
	pWL->WritePair("Name", GetName());
	pWL->WritePair("Font", GetFont());
	pWL->WritePair("Text", m_Text.m_OriginalText);
	pWL->WritePair("Underline", GetUnderline());
	pWL->WritePair("BlockAll", m_BlockAllEvents);

	if (m_pSkin)
	{
		pWL->WritePair("SkinElement", m_pSkin->Name);
	}
	if (m_UseMask)
	{
		pWL->WritePair("UseMask", 1);
	}
	if(m_IsRenderRotated)
	{
		pWL->WritePair("IsRenderRotated", 1);
	}
	
	// text layout
	pWL->WritePair("BorderSize", GetTextBorder());

	// graphics
	math::Vec2	Pos = GetPosition();
	if (m_pParent)
		Pos -= m_pParent->GetPosition();
	pWL->WritePair("Pos", Pos);
	pWL->WritePair("Size", GetSize());
	pWL->WritePair("UV1", m_BaseUV1);
	pWL->WritePair("UV2", m_BaseUV2);

	math::Vec4	Color;
	Color.w = ((m_Color & 0xFF000000) >> 24) * (1.0f / 255.0f);
	Color.z = ((m_Color & 0x00FF0000) >> 16) * (1.0f / 255.0f);
	Color.y = ((m_Color & 0x0000FF00) >> 8 ) * (1.0f / 255.0f);
	Color.x = ((m_Color & 0x000000FF)      ) * (1.0f / 255.0f);
	pWL->WritePair("Color", Color);
	pWL->WritePair("Additive", IsAdditive() ? 1 : 0);


	pWL->WritePair("Rotation", GetRotation());

	if (!m_NextWidget.empty())
		pWL->WritePair("Next", m_NextWidget);


	UIText::TEXT_JUST_VERT	vjust = m_Text.GetVertJust();
	UIText::TEXT_JUST_HORIZ	hjust = m_Text.GetHorizJust();

	if (hjust == UIText::TJH_CENTER)	pWL->WritePair("HJust", "center"); else
	if (hjust == UIText::TJH_LEFT)		pWL->WritePair("HJust", "left"); else
	if (hjust == UIText::TJH_RIGHT)		pWL->WritePair("HJust", "right");

	if (vjust == UIText::TJV_CENTER)	pWL->WritePair("VJust", "center"); else
	if (vjust == UIText::TJV_TOP)		pWL->WritePair("VJust", "top"); else
	if (vjust == UIText::TJV_BOTTOM)	pWL->WritePair("VJust", "bottom");

	if (m_Text.GetMaxInputLen() != UIText::DEFAULT_MAX_INPUT_LEN)
		pWL->WritePair("MaxInput", m_Text.GetMaxInputLen());

	if (m_Text.IsEditable())
		pWL->WritePair("CanEdit", 1);
	if (m_Text.CanEditMultiline())
		pWL->WritePair("CanEditMultiline", 1);
	if (m_CanDrag)
		pWL->WritePair("CanDrag", 1);
	if (!m_IsActive)
		pWL->WritePair("Active", 0);
	if (m_IsPassword)
		pWL->WritePair("IsPassword", 1);

	if (!m_PlaySound)
		pWL->WritePair("PlaySoundEvent", 0);

	if (m_DisableOverSound)
		pWL->WritePair("DisableOverSound", 1);

	if (m_DisableClickSound)
		pWL->WritePair("DisableClickSound", 1);

	math::Vec4	TextColor;
	TextColor.w = ((m_Text.GetColor()& 0xFF000000) >> 24) * (1.0f / 255.0f);
	TextColor.z = ((m_Text.GetColor() & 0x00FF0000) >> 16) * (1.0f / 255.0f);
	TextColor.y = ((m_Text.GetColor() & 0x0000FF00) >> 8 ) * (1.0f / 255.0f);
	TextColor.x = ((m_Text.GetColor() & 0x000000FF)      ) * (1.0f / 255.0f);
	pWL->WritePair("TextColor", TextColor);
	pWL->WritePair("Type", GetTypeName());


	// todo: export timeline

	// export all images
	if (m_ImageA[WS_MOUSE_OFF].IsValid())	pWL->WritePair("MouseOff", m_ImageA[WS_MOUSE_OFF].GetFilename());
	if (m_ImageA[WS_MOUSE_OVER].IsValid())	pWL->WritePair("MouseOver", m_ImageA[WS_MOUSE_OVER].GetFilename());
	if (m_ImageA[WS_MOUSE_CLICK].IsValid())	pWL->WritePair("MouseClick", m_ImageA[WS_MOUSE_CLICK].GetFilename());

	// export widget specifics
	ExportSpecificsToFile(pWL);


	// export all events
	for (unsigned int i=0; i<WE_COUNT; i++)
	{
		const std::string&	Evt = GetEvent((WIDGET_EVENT)i);
		if (!Evt.empty())
		{
			std::string	Entry = GetStringFromEvent((WIDGET_EVENT)i);
			pWL->WritePair(Entry, Evt);
		}
	}
	// export children
	if (!m_Set.empty())
	{
		pWL->StartTable("Children");
			for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
			{
				pWL->StartTable("-- Child entry");
					It->second->ExportToFile(pWL);
				pWL->CloseTable();
			}
		pWL->CloseTable();
	}
	return true;
}

bool		UIWidget::ExportSpecificsToFile(script::WriteLua*	pWL)
{
//	pWL->WritePair("Type", "widget");
	return true;
}


bool		UIWidget::AddChild(UIWidget* pChild)
{
	/*
	if (!pChild || pChild->GetName().empty())
		return false;
	AddElementBack(pChild->GetName(), pChild);
	pChild->m_pParent = this;
	return true;
	*/
	return InsertChild(pChild, false, "");
}

bool		UIWidget::InsertChild(UIWidget* pChild, bool bInsertBefore, ui::UIWidget* pRef)
{
	return InsertChild(pChild, bInsertBefore, pRef ? pRef->GetName() : "");
}

bool		UIWidget::InsertChild(UIWidget* pChild, bool bInsertBefore, const std::string& Ref)
{
	if (!pChild || pChild->GetName().empty())
		return false;

	if (Ref.empty())
	{
		if (bInsertBefore)
			AddElementFront(pChild->GetName(), pChild);
		else
			AddElementBack(pChild->GetName(), pChild);
	}
	else
	{
		InsertBefore(pChild->GetName(), pChild, Ref);
/*		if (bInsertBefore)
			InsertBefore(pChild->GetName(), pChild, Ref);
		else
			InsertAfter(pChild->GetName(), pChild, Ref);
*/	}

	pChild->m_pParent = this;
	return true;
}

bool		UIWidget::RemoveChild(UIWidget* pChild, bool Delete)
{
	if (!pChild || pChild->GetName().empty())
		return false;

	RemoveElement(pChild->GetName(), Delete);
	return true;
}

bool				UIWidget::RenameWidget(const std::string& NewName)
{
	if (m_pParent)
	{
		m_pParent->RemoveElement(GetName(), false);
		m_Name = NewName;
		m_pParent->AddElementBack(GetName(), this);
	} else
	{
		ui::UIManager::Instance().DropPanel(this, false);
		m_Name = NewName;
		ui::UIManager::Instance().AddWidget(this);
	}

	
	return true;

}


bool		UIWidget::Tick(float dt)
{
	// update movers
	if (!m_MoverList.empty())
	{	
		// delete any invalidated ones
		for (int i=(int)(m_MoverList.size())-1; i>=0; i--)
		{
			if (m_MoverList[i]->IsFinished() && !m_MoverList[i]->IsRunningScript())
			{
				delete m_MoverList[i];
				m_MoverList.erase(m_MoverList.begin()+i);
			}
		}
	}
	// update what remains
	if (m_MoverList.size() >0)
	{	
		UIMover* pMover = m_MoverList[0];
		if (!pMover->IsFinished() )
		{
			pMover->Tick(dt);
			if (pMover->IsFinished())
			{
				pMover->Invalidate();
			}
		} 
	}

	if (!m_IsVisible)
		return false;	// disable entire widget


	m_MouseOverEvent = m_MouseOffEvent = false;

#ifdef _PLATFORM_WII
	if (this == m_pManager->GetSelected())
	{
		m_CurrentState = WS_MOUSE_OVER;
	} else
	{
		m_CurrentState = WS_MOUSE_OFF;
	}
#endif

	// update image
	if (m_ImageA[m_CurrentState].IsValid())
	{
		if (m_ImageA[m_CurrentState].Tick(dt))
		{
			if (!m_NextImageA[m_CurrentState].empty())
			{
				m_ImageA[m_CurrentState].SetImage(m_NextImageA[m_CurrentState]);
				m_NextImageA[m_CurrentState].resize(0);
			}
		}
	} else
	{
		if (m_ImageA[WI_MOUSE_OFF].Tick(dt))
		{
		//	TriggerEvent(WE_CLIP_ENDED);
		}
	}

	// update children
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		It->second->Tick(dt);

	if(!m_IsImagedLoaded)
	{
		for(int i = 0 ; i < WI_COUNT; i++)
		{
			m_ImageA[i].Tick(0);	// load images
		}
		m_IsImagedLoaded = true;
	}

	return true;
}

void		UIWidget::GetUV( math::Vec2& UV1, math::Vec2& UV2)
{
	if (m_ImageA[m_CurrentState].IsValid())
	{
		UV1 = m_ImageA[m_CurrentState].GetUV1();
		UV2 = m_ImageA[m_CurrentState].GetUV2();
		return;
	}
	else
	{
		if (m_ImageA[WS_MOUSE_OFF].IsValid())
		{
			UV1 = m_ImageA[WS_MOUSE_OFF].GetUV1();
			UV2 = m_ImageA[WS_MOUSE_OFF].GetUV2();
			return;
		}
	}
	UV1 = m_BaseUV1;
	UV2 = m_BaseUV2;
}


void UIWidget::PostRender()
{
	if (!m_IsVisible  || !m_IsActive) return;
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
			It->second->PostRender();
	}
	// render hover
	if (m_CurrentState == WS_MOUSE_OVER && m_OverMode > WO_NONE) 
	{
		UISprite& sprite = m_ImageA[WS_MOUSE_OFF];
		if (sprite.IsValid()) {
			const math::Vec2 margin(5.0f/(float)GraphicsUtil::WIDTH,5.0f/(float)GraphicsUtil::HEIGHT);

			math::Vec2 overPos = m_Pos;
			math::Vec2 overSize = sprite.GetImageSize();

			if (m_OverMode == WO_SCREEN_CENTERED) {
				overPos = math::Vec2(1.0f/400.0f,1.0f/300.0f);
				overPos -= overSize / 2.0f;
			}
			else if (m_OverMode == WO_CENTERED) {
				overPos += m_Size / 2.0f;
				overPos -= overSize / 2.0f;
			}

			// if overflow move to the left of the position
			if (overPos.x + overSize.x > 1.0f)	overPos.x = 1.0f-overSize.x-margin.x;
			// if overflow move to the top of the position
			if (overPos.y + overSize.y > 1.0f) overPos.y = 1.0f-overSize.y-margin.y; 
			// move pos to 0,0 if necessary
			if (overPos.x < 0) overPos.x = margin.x;
			if (overPos.y < 0) overPos.y = margin.y;

			Graphics::Vertex2D	verts[6];
			GraphicsUtil::FillQuad(overPos-margin, overSize+(margin*2.0f), 
								   math::Vec2(0,0),math::Vec2(0,0), 0xAA88AA88, verts);

			GetGraphics()->DrawVertex2D(verts,6);
			sprite.Setup(overPos+margin,overSize,0,1,m_Color);
			sprite.Render();
		}
	}
}

bool		UIWidget::Render(bool Force)
{
	if (!Force)
	{
		// look for things that could disqualify this one from being rendered
		if (!m_IsVisible)
			return false;	// disable entire widget
		if (m_pManager->GetDragTarget() == this)
			return false;	// will get rendered on top anyways
	}


	if (m_pManager) m_pManager->WidgetRendered();

	// ADRIAN: render mover
	if (!m_MoverList.empty()) m_MoverList[0]->RenderBackground();
	
	if (m_MoverList.empty() || m_MoverList[0]->RenderSelf()) // ADRIAN: check mover widget behavior
	{
		// render self
		if (m_pSkin)
		{
			m_pSkin->Render(UISkinData::IMAGE_STATES(m_CurrentState), m_Pos, m_Size, m_Color);
		} else
		{
			assert(m_CurrentState <WS_COUNT && "Current state is illegal!");
			if (m_ImageA[m_CurrentState].IsValid())
			{
				m_ImageA[m_CurrentState].Setup(m_Pos, m_Size, m_Rotation, m_Scale, m_Color);
				if(m_IsRenderRotated)
					m_ImageA[m_CurrentState].RenderRotated();
				else
					m_ImageA[m_CurrentState].Render();
			}
			else
			{
				if (m_ImageA[WS_MOUSE_OFF].IsValid())
				{
					m_ImageA[WS_MOUSE_OFF].Setup(m_Pos, m_Size, m_Rotation, m_Scale, m_Color);
					if(m_IsRenderRotated)
						m_ImageA[WS_MOUSE_OFF].RenderRotated();
					else
						m_ImageA[WS_MOUSE_OFF].Render();
				}
			}
		}
	}
	
	if (m_MoverList.empty() || m_MoverList[0]->RenderChildren()) // ADRIAN: check mover widget behavior
	{
		// render text
		m_Text.Render();
		
		// render drop-downs after normals?
		for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		{
			It->second->Render();
		}
	}
	
	// ADRIAN: render mover
	if (!m_MoverList.empty()) m_MoverList[0]->RenderForeground();
	
	return true;
}

void		UIWidget::RenderHooverTip()
{
	if (!m_IsHoovering) 
		return;

	// render the hoover-text here.

	m_IsHoovering = false;
}


bool				UIWidget::IsValid(WIDGET_STATE state)
{
	assert(state < WS_COUNT && state >= 0 && "Illegal state!");
	return (m_ImageA[state].m_pImage != NULL);
}

void				UIWidget::SetPosition(const math::Vec2& Pos)
{
	math::Vec2	OldPos = m_Pos;
	m_Pos = Pos;	
	if (m_pParent)
	{
		m_Pos = m_pParent->m_Pos + Pos;	
	}

	m_Text.SetExtents(m_Pos, m_Size);
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		math::Vec2	ChildPos = It->second->m_Pos;
		It->second->SetPosition(ChildPos - OldPos);
	}
}

void		UIWidget::SetPositionRelativeToParent(const math::Vec2& Pos)
{
	if (m_pParent)
	{
		SetPosition(Pos - m_pParent->m_Pos);
	} else
	{
		SetPosition(Pos);
	}
}

void				UIWidget::SetIsActive(bool b)
{
	m_IsActive = b;

	/* ADRIAN: who is responsible for this???
	// are we a panel?
	if (m_IsActive && !m_pParent && ReAdd)
	{
		// add it to the end of the set
		if (m_pManager->DropPanel(this, false))
			m_pManager->AddWidget(this);
	}
	*/
}

void				UIWidget::SetIsVisible(bool b)
{
	m_IsVisible = b;
}

bool				UIWidget::IsParentVisible() const
{
	if (!m_pParent) return m_IsVisible;
	if (!m_IsVisible) return false;
	return m_pParent->IsParentVisible();
}


void				UIWidget::SetSize(const math::Vec2& Size)
{
	m_Size = Size;
	m_Text.m_Size = Size;
}

void				UIWidget::SetTextColor(float r, float g, float b, float a)
{
	m_Text.SetColor(ColorfRGBA(r, g, b, a));
}

void				UIWidget::SetColor(float r, float g, float b, float a)
{
	m_Color = ColorfRGBA(r, g, b, a);
}

void				UIWidget::SetScale(float Scale)
{
	m_Scale = Scale;
	// scale children?
}

void				UIWidget::SetRotation(float Rot)
{
	float Delta = Rot - m_Rotation;
	m_Rotation = Rot;
	
/*	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		float ChildRot = It->second->m_Rotation;
		It->second->SetRotation(ChildRot + Delta);
	}*/
}

void				UIWidget::SetUV(const math::Vec2& UV1, const math::Vec2& UV2)
{
	m_ImageA[m_CurrentState].m_UV1 = UV1;
	m_ImageA[m_CurrentState].m_UV2 = UV2;
}

void	UIWidget::SetTextA(const std::string& Text)
{
	SetTextW(lang::Lang::ConvertAtoW(Text));
}


void	UIWidget::SetTextW(const std::wstring& Text)
{
	m_Text.SetOwner(this);
	m_Text.SetExtents(m_Pos, m_Size);
	m_Text.SetText(Text);
}

void	UIWidget::AppendTextA(const std::string& Text)
{
	AppendTextW(lang::Lang::ConvertAtoW(Text));
}

void	UIWidget::AppendTextW(const std::wstring& Text)
{
	m_Text.AppendText(Text);
}


void	UIWidget::SelectAllText()
{
	m_Text.SelectAll();
}

const std::wstring&		UIWidget::GetText()
{
	return	m_Text.GetText();
}


std::string	UIWidget::GetOrigTextA()
{
	return	lang::Lang::ConvertWtoA(m_Text.m_OriginalText);
}

std::string 	UIWidget::GetTextA()
{
	return	lang::Lang::ConvertWtoA(m_Text.GetText());
}

void				UIWidget::SetFont(const std::string& Text)
{
	m_Text.SetFont(Text);
}

const std::string&	UIWidget::GetFont()
{
	return m_Text.GetFontName();
}

const math::Vec2&	UIWidget::GetTextBorder()
{
	return m_Text.GetBorder();
}

void	UIWidget::SetTextBorder(const math::Vec2& Size)
{
	return m_Text.SetBorder(Size);
}


std::string			UIWidget::GetVAlign()
{
	return m_Text.GetVertJustText();
}
void				UIWidget::SetVAlign(const std::string& Align)
{
	m_Text.SetVertJust(Align);
}

std::string			UIWidget::GetHAlign()
{
	return m_Text.GetHorizJustText();
}
void				UIWidget::SetHAlign(const std::string& Align)
{
	m_Text.SetHorizJust(Align);
}



void				UIWidget::ResizeToText()
{
	if (m_Text.GetText().size() < 1)
		return;

	m_Size.y = 1.0f;

	m_Text.SetOwner(this);
	m_Text.SetExtents(m_Pos, m_Size);
	//m_Text.SetText(m_Text.GetText()); // ADRIAN: don't use this, this will replace any localization-based string
	m_Text.SetText(m_Text.GetOrigText());

	m_Size = m_Text.GetSize();
	m_Size.x += 0.01f;
	m_Size.y += 0.01f;

}




void				UIWidget::SetCanEdit(bool b)
{
	m_Text.SetCanEdit(b);
}

bool				UIWidget::GetCanEdit() const 
{
	return m_Text.IsEditable();
}

void				UIWidget::SetCanEditMultiline(bool b)
{
	m_Text.SetCanEditMultiline(b);
}

bool				UIWidget::GetCanEditMultiline() const
{
	return m_Text.CanEditMultiline();
}


UIWidget*			UIWidget::GetWidgetByNameEx(const char* Name, ...)
{
	char Message[1024];
	va_list ArgP;
	va_start(ArgP, Name);
	vsprintf(Message, Name, ArgP);
	va_end(ArgP);

	return GetWidgetByName(Message);
}


UIWidget*			UIWidget::GetWidgetByName(const std::string& Name)
{

	if (strcmpi(m_Name.c_str(), Name.c_str()) == 0)
		return this;
	{
		for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		{
			UIWidget* pFound = It->second->GetWidgetByName(Name);
			if (pFound)
				return pFound;
		}
	}
	return NULL;
}

UISlider*			UIWidget::GetSliderByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_SLIDER)
	{
		return (UISlider*)pWidget;
	}
	return NULL;
}

UIProgress*			UIWidget::GetProgressByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_PROGRESS)
	{
		return (UIProgress*)pWidget;
	}
	return NULL;
}

UIMultiLine*		UIWidget::GetMultiLineByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_MULTILINE)
	{
		return (UIMultiLine*)pWidget;
	}
	return NULL;
}

UIDropDown*			UIWidget::GetDropDownByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_DROPDOWN)
	{
		return (UIDropDown*)pWidget;
	}
	return NULL;
}

UICheckBox*			UIWidget::GetCheckBoxByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_CHECKBOX)
	{
		return (UICheckBox*)pWidget;
	}
	return NULL;
}

UIMovieWidget*		UIWidget::GetMovieWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_MOVIEWIDGET)
	{
		return (UIMovieWidget*)pWidget;
	}
	return NULL;

}

UIListWidget*		UIWidget::GetListWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_LIST)
	{
		return (UIListWidget*)pWidget;
	}
	return NULL;
}

UIFlexEffect*		UIWidget::GetFlexWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_FLEXEFFECT)
	{
		return (UIFlexEffect*)pWidget;
	}
	return NULL;
}

UIBipedWidget*		UIWidget::GetBipedWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_BIPED)
	{
		return (UIBipedWidget*)pWidget;
	}
	return NULL;
}

UIDragWidget*		UIWidget::GetDragWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_DRAG)
	{
		return (UIDragWidget*)pWidget;
	}
	return NULL;
}

UIGraph*			UIWidget::GetGraphWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_GRAPH)
	{
		return (UIGraph*)pWidget;
	}
	return NULL;
}

UIPolyLine*			UIWidget::GetPolyLineWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_POLYLINE)
	{
		return (UIPolyLine*)pWidget;
	}
	return NULL;
}

UICalendar*			UIWidget::GetCalendarWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_CALENDAR)
	{
		return (UICalendar*)pWidget;
	}
	return NULL;
}

#ifndef _PLATFORM_WII
UIFlashWidget*		UIWidget::GetFlashWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_FLASHWIDGET)
	{
		return (UIFlashWidget*)pWidget;
	}
	return NULL;
}
#endif //_PLATFORM_WII


UIPart2DWidget*		UIWidget::GetPartWidgetByName(const std::string& Name)
{
	UIWidget*	pWidget = GetWidgetByName(Name);
	if (pWidget && pWidget->GetType() == WT_PART2DWIDGET)
	{
		return (UIPart2DWidget*)pWidget;
	}
	return NULL;
}



void			UIWidget::GetWidgetsThatHaveTextInName(const std::string& TextInName, std::vector<UIWidget*>& SearchResult)
{
	std::string::size_type SearchLoc = m_Name.find(TextInName);

	if (SearchLoc != std::string::npos)
		SearchResult.push_back(this);

	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		UIWidget* pCurChild;
		pCurChild = (It->second);

		if (pCurChild != NULL)
			pCurChild->GetWidgetsThatHaveTextInName(TextInName, SearchResult); 
	}

}




bool				UIWidget::SetEvent(WIDGET_EVENT Event, const std::string& Script)
{
	assert(Event < WE_COUNT && Event >= 0 && "Illegal range for event!");
	m_EventA[Event] = Script;
	return true;
}

const std::string&	UIWidget::GetEvent(WIDGET_EVENT Event) const
{
	assert(Event < WE_COUNT && Event >= 0 && "Illegal range for event!");
	return m_EventA[Event];
}


UIWidget*			UIWidget::GetTriggerWidget()
{
	if (!IsActive()) return NULL;
	if (!m_NextWidget.empty()) return this;
	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		UIWidget* pWidget = It->second->GetTriggerWidget();
		if (pWidget) return pWidget;
	}
	return NULL;
}

bool				UIWidget::TriggerEvent(WIDGET_EVENT Event)
{
	assert(Event < WE_COUNT && Event >= 0 && "Illegal range for event!");

	bool ret = false;
	if (m_EventDg[Event]) 
	{
		m_EventDg[Event](Event,this);
		ret = true;
	}
	if (Event == WE_TAB_KEY || Event == WE_RIGHT_KEY)
	{
		if (!m_NextWidget.empty() && GetPanel())
		{
			ui::UIWidget*	pWidget = GetPanel()->GetWidgetByName(m_NextWidget);
			if (pWidget)
			{
				m_pManager->SetSelected(pWidget);
				if (pWidget->GetCanEdit())
					m_pManager->SetEditWidget(pWidget);

				ProcessMouseOff();
				pWidget->ProcessMouseOver();
				pWidget->SelectAllText();
			}
		}
		return true;
	} else
	if (Event == WE_LEFT_KEY)
	{
		if (!m_PrevWidget.empty() && GetPanel())
		{
			ui::UIWidget*	pWidget = GetPanel()->GetWidgetByName(m_PrevWidget);
			if (pWidget)
			{
				m_pManager->SetSelected(pWidget);
				if (pWidget->GetCanEdit())
					m_pManager->SetEditWidget(pWidget);

				ProcessMouseOff();
				pWidget->ProcessMouseOver();
				pWidget->SelectAllText();
			}
		}
		return true;
	} else
	if (Event == WE_TEXT_ENTER)
	{
		OnMouseRelease(m_Pos + (m_Size * 0.5f), 0);
	} else
	if (!m_EventA[Event].empty())
	{
		// execute in which state ?
		console::Console::Instance().Do(m_EventA[Event]);
		ret = true;
	}

	return ret;
}

bool				UIWidget::OnMouseMove(const math::Vec2& From, const math::Vec2& To)
{
	if (!m_IsActive || !m_IsVisible)
	{
		return false;
	}

	bool	InsideFrom = IsInside(From);
	bool	InsideTo   = IsInside(To);

	if (InsideTo)
	{
		m_CurrentState = WS_MOUSE_OVER;
	} else
	{
		m_CurrentState = WS_MOUSE_OFF;
	}

	m_IsHoovering = InsideTo;
	m_MouseOverEvent = false;
	m_MouseOffEvent = false;

	if ( InsideFrom&& !InsideTo)
	{
		m_MouseOffEvent = true;
	} else
	if (!InsideFrom && InsideTo)
	{
		m_MouseOverEvent = true;
	}

	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		if (It->second->OnMouseMove(From, To)) return true;
	}

	return InsideTo && m_BlockAllEvents;
	//return m_BlockAllEvents;
}

bool UIWidget::ProcessMouseOver()
{
	bool ret = false;

	if (m_IsHoovering == true && m_HooverTip != "" && m_IsVisible == true)
		UIManager::Instance().SetCurTipID(m_HooverTip);

	if (m_MouseOverEvent )
	{
		if (TriggerEvent(WE_MOUSE_OVER) || m_ImageA[WS_MOUSE_OVER].IsValid())
		{
			ret = true;
			if (m_PlaySound && !m_DisableOverSound)
			{
				AUDIO().PlayEvent("BUTTON_OVER");
			}
		}

	}
	
	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		bool Res = It->second->ProcessMouseOver();
		if (Res) return true;
	}

	return ret;
	//return m_BlockAllEvents;
}

bool UIWidget::ProcessMouseOff()
{
	bool ret = false;

	if (m_MouseOffEvent )
	{
		ret = TriggerEvent(WE_MOUSE_OFF);
	}
	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		bool Res = It->second->ProcessMouseOff();
		if (Res) return true;
	}
	return ret;
	//return m_BlockAllEvents;
}

void		UIWidget::RefreshFonts()
{
	m_Text.SetFont(m_Text.GetFontName());
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		It->second->RefreshFonts();
}

void				UIWidget::RefreshText()
{
	m_Text.RefreshText();
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		It->second->RefreshText();
}


bool				UIWidget::OnMouseDrag(const math::Vec2& From, const math::Vec2& To)
{
	if (!m_IsActive || !m_IsVisible)
	{
		return false;
	}

	// is it currently inside?
	// or is it the current drag target
	if ((IsInside(From) || m_pManager->GetDragTarget() == this)
		&& m_CanDrag)
	{
		math::Vec2	Offset;
		if (m_pParent)
			Offset = m_pParent->GetPosition();
		SetPosition(To - Offset - (m_Size * 0.1f));
		UIManager::Instance().SetFocus(this);
		UIManager::Instance().SetDragTarget(this);

		return true;
	}

	if (!UIManager::Instance().GetDragTarget())
	{
		UIManager::Instance().SetFocus(this);
	}


	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		if (It->second->OnMouseDrag(From, To))
			return true;
	}


	return m_BlockAllEvents && IsInside(To);
	//return false;
	//return m_BlockAllEvents;
}

bool				UIWidget::OnMouseDrop(const math::Vec2& From, const math::Vec2& To, UIWidget* pDroppedWidget)
{
	bool ret = false;
	if (!m_IsActive || !m_IsVisible)
	{
		return false;
	}
	if (IsInside(To))
	{
		//int i = 0;
		ret = true;
	}

	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
		It->second->OnMouseDrop(From, To, pDroppedWidget);

	return ret;
	//return m_BlockAllEvents;

}

bool				UIWidget::OnMouseHoover(const math::Vec2& Pos)
{
	/// assume that all children are inside the volume of the parent?
	if (!m_IsActive || !m_IsVisible || !IsInside(Pos))
	{
		return false;
	}

	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		It->second->OnMouseHoover(Pos);

	if (!m_HooverTip.empty())
	{
		m_IsHoovering = true;
		return true;
	} 
	return m_BlockAllEvents;
}

bool				UIWidget::OnMouseDown(const math::Vec2& Pos, unsigned int Button)
{
	/// assume that all children are inside the volume of the parent?
 	if (!m_IsActive || !m_IsVisible)
	{
		return false;
	}

	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		if (It->second->OnMouseDown(Pos, Button))
			return true;
	}

	
	
	if (IsValid(WS_MOUSE_CLICK) && IsInside(Pos) )
	{
		m_CurrentState = WS_MOUSE_CLICK;
		return true;
	}
	

	return m_BlockAllEvents && IsInside(Pos);
	//return false;
	//return m_BlockAllEvents;
}


bool		UIWidget::OnMouseRepeat(const math::Vec2& Pos, unsigned int Button)
{
	/// assume that all children are inside the volume of the parent?
	if (!m_IsActive || !m_IsVisible )
	{
		return false;
	}

	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		if (It->second->OnMouseRepeat(Pos, Button))
			return true;
	}

	if (IsInside(Pos))
	{
		if (Button == 0)
			return TriggerEvent(WE_LMB_REPEAT);
		else
			return TriggerEvent(WE_RMB_REPEAT);

		if (IsValid(WS_MOUSE_CLICK))
		{
			m_CurrentState = WS_MOUSE_CLICK;
			return true;
		}
	}

	return false;
	//return m_BlockAllEvents;
}


bool				UIWidget::OnMousePress(const math::Vec2& Pos, unsigned int Button)
{
	/// assume that all children are inside the volume of the parent?
	if (!m_IsActive || !m_IsVisible )
	{
		return false;
	}

	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		if (It->second->OnMousePress(Pos, Button))
			return true;
	}

	if (IsInside(Pos))
	{
		if (Button == 0)
		{
			if (m_Text.IsEditable())
			{
				m_Text.PutCursor(Pos);
			}
			if (TriggerEvent(WE_LMB_CLICK))
			{
				return true;
			}
		}
		else
		{
			if (TriggerEvent(WE_RMB_CLICK))
				return true;
		}
		return m_BlockAllEvents;
	}

	return false;
	//return m_BlockAllEvents;
}


bool				UIWidget::OnMouseDblClick(const math::Vec2& Pos, unsigned int Button)
{
	/// assume that all children are inside the volume of the parent?
	if (!m_IsActive || !m_IsVisible )
	{
		return false;
	}

	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		if (It->second->OnMouseDblClick(Pos, Button))
			return true;
	}

	if (IsInside(Pos))
	{
		if (Button == 0)
		{
			if (TriggerEvent(WE_LMB_DBL_CLICK))
				return true;
		}
		else
		{
			if (TriggerEvent(WE_RMB_DBL_CLICK))
				return true;
		}

		if (IsInside(Pos))
		{
			m_CurrentState = WS_MOUSE_OVER;
		}
		else
			m_CurrentState = WS_MOUSE_OFF;

		return m_BlockAllEvents;
	}

	return false;
	//return m_BlockAllEvents;
}

bool				UIWidget::OnMouseRelease(const math::Vec2& Pos, unsigned int Button)
{
	/// assume that all children are inside the volume of the parent?
	if (!m_IsActive || !m_IsVisible )
	{
		return false;
	}

	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		if (It->second->OnMouseRelease(Pos, Button))
			return true;
	}

	if (IsInside(Pos))
	{
		m_CurrentState = WS_MOUSE_OVER;
	}
	else
		m_CurrentState = WS_MOUSE_OFF;


	if (IsInside(Pos))
	{
		if (Button == 0)
		{
			if (m_Text.IsEditable() && m_pManager->GetEditText() != &m_Text)
			{
				m_pManager->SetEditWidget(this);
			}
			UIManager::Instance().SetFocus(this);

			if (!m_EventA[WE_LMB_RELEASE].empty() || m_EventDg[WE_LMB_RELEASE])
			{
				if (m_PlaySound && !m_DisableClickSound)
				{
					AUDIO().PlayEvent("button_press");
				}
			}

			bool Trigger = TriggerEvent(WE_LMB_RELEASE);
			return m_BlockAllEvents || Trigger || m_Text.IsEditable() || m_CanDrag;	// Fixme: this is to force focus on the child, rather than the parent
		}
		else
			return m_BlockAllEvents || TriggerEvent(WE_RMB_RELEASE);
	}
	return false;
}

void				UIWidget::GetChildren(std::vector<UIWidget*>& Children)
{
	Children.resize(0);
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		Children.push_back(It->second);
	}
}

UIWidget*			UIWidget::GetWidgetAtPos(const math::Vec2& Pos)
{
	if (!m_IsVisible )
	{
		return NULL;
	}
	for (ElementList::reverse_iterator It = m_Set.rbegin(); It != m_Set.rend(); It++)
	{
		UIWidget* pFound = It->second->GetWidgetAtPos(Pos);
		if (pFound) return pFound;
	}
	if (!IsInside(Pos))
		return NULL;
	return this;
}

void				UIWidget::SetName(const std::string& Name)
{
	if (m_pParent)
	{
		// notify parent to keep table up to data?
		m_pParent->RemoveElement(m_Name, false);	// drop from table, do not delete
		m_Name = Name;
		m_pParent->AddElementBack(m_Name, this);
	} else
	{
		m_Name = Name;
	}
}

void		UIWidget::UpdateLocalization()
{
	for (int i=0; i<WI_COUNT; i++)
		m_ImageA[i].UpdateLocalization();
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		It->second->UpdateLocalization();
}

UIWidget*			UIWidget::GetPanel()
{
	if (m_pParent)	return m_pParent->GetPanel();
	return this;
}

bool				UIWidget::OnKeyEvent(const input::Keyboard::KEY& Key)
{
	if (!m_IsActive)
	{
		return false;
	}

	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		It->second->OnKeyEvent(Key);

	return false;
}

void		UIWidget::ResetResources()
{
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		It->second->ResetResources();
}

bool				UIWidget::IsInside(const math::Vec2& Point)
{
	float MIN1 = m_Pos.x;
	float MAX1 = m_Pos.x + m_Size.x;
	float MIN2 = m_Pos.y;
	float MAX2 = m_Pos.y + m_Size.y;
	if(IsRenderRotated())
	{
		
		MIN1 = m_Pos.x - (m_Size.x * 0.5f);
		MAX1 = m_Pos.x + (m_Size.x * 0.5f);
		MIN2 = m_Pos.y - (m_Size.y * 0.5f);
		MAX2 = m_Pos.y + (m_Size.y * 0.5f);
	}
	

	if ( UTIL_RANGE(Point.x, MIN1, MAX1) && UTIL_RANGE(Point.y, MIN2, MAX2))
	{
		if (m_UseMask)
		{
			if (m_ImageA[m_CurrentState].IsValid() && m_ImageA[m_CurrentState].HasMask())
				return m_ImageA[m_CurrentState].IsInsideMask(Point);
			else if ((WS_MOUSE_OFF != m_CurrentState) && m_ImageA[WS_MOUSE_OFF].IsValid() && m_ImageA[WS_MOUSE_OFF].HasMask())
				return m_ImageA[WS_MOUSE_OFF].IsInsideMask(Point);
		}
		return true;
	}
	return false;
}

bool		UIWidget::IsImageValid()
{
	return m_pSkin || m_ImageA[m_CurrentState].IsValid() || m_ImageA[WI_MOUSE_OFF].IsValid();
}

bool				UIWidget::CursorInsideWidget(const math::Vec2& Pos)
{
	if (!IsVisible()) return false;
	if (IsInside(Pos) && IsImageValid()) 
		return true;

	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		if (It->second->CursorInsideWidget(Pos))
			return true;
	}
	return false;
}

bool				UIWidget::CursorInsideActiveWidget(const math::Vec2& Pos)
{
	if (!IsVisible()) return false;
	if (IsInside(Pos) && IsImageValid()) 
	{
		// check that there's a valid event here as well
		if (m_BlockAllEvents) return true;
		if (!m_EventA[WE_LMB_CLICK].empty())	return true;
		if (!m_EventA[WE_LMB_RELEASE].empty())	return true;
	}

	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		if (It->second->CursorInsideActiveWidget(Pos))
			return true;
	}
	return false;
}

math::Vec2	UIWidget::GetPositionRelativeToParent() const
{
	if (GetParent())
		return m_Pos - GetParent()->GetPosition();
	return m_Pos;
}

void		UIWidget::RecalcSize()
{
	if (m_ImageA[m_CurrentState].IsValid())
		m_ImageA[m_CurrentState].GetScreenSize(m_Size);
}

void		UIWidget::FitToRect(const math::Vec2& Rect)
{
	if (!m_ImageA[WI_MOUSE_OFF].IsValid()) return;
	math::Vec2	Size;
	m_ImageA[WI_MOUSE_OFF].GetScreenSize(Size);

	float	xasp = Size.x / Rect.x;
	float	yasp = Size.y / Rect.y;

	if (xasp >yasp)
	{
		m_Size.x = Rect.x;
		m_Size.y = Size.y * (m_Size.x/Size.x);
	}	else
	{
		m_Size.y = Rect.y;
		m_Size.x = Size.x * (m_Size.y/Size.y);
	}
}

bool		UIWidget::HasAnimation()
{
	if (!IsVisible()) return false;
	if (m_MoverList.size() > 0) 
		return true;
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		if (It->second->HasAnimation()) return true;
	}
	return false;

}
void		UIWidget::DropMover(UIMover* pMover)
{
	// does it exist?
	for (unsigned int i=0; i<m_MoverList.size(); i++)
	{
		if (m_MoverList[i]==pMover)
		{
			m_MoverList.erase(m_MoverList.begin()+i);
			delete pMover;
			return;
		}
	}
	assert(!"Trying to delete invalid mover!");
}

void		UIWidget::AddMover(UIMover* pMover)
{
	m_MoverList.push_back(pMover);
}

UIWidget::WIDGET_EVENT		UIWidget::GetEventFromString(const std::string& Name) 
{
	// convert to lower-case
	std::string	upr = Name;
    std::transform(upr.begin(), upr.end(), upr.begin(), tolower);

	for (int i=0; i<WE_COUNT; i++)
	{
		if (upr == GetStringFromEvent((WIDGET_EVENT)i)) return (WIDGET_EVENT)i;
	}	
	return WE_UNKNOWN;
}

std::string			UIWidget::GetStringFromEvent(WIDGET_EVENT Event)
{
	switch (Event)
	{
		case WE_ON_LOAD:		return "on_load";
		case WE_GAIN_FOCUS:		return "gain_focus";
		case WE_LOOSE_FOCUS:	return "loose_focus";
		case WE_DRAG:			return "drag";
		case WE_DROP:			return "drop";
		case WE_MOUSE_OVER:		return "mouse_over"; 
		case WE_MOUSE_OFF:		return "mouse_off";
		case WE_MOUSE_HOOVER:	return "hoover";
		case WE_LMB_CLICK:		return "lmb_click";
		case WE_LMB_DBL_CLICK:	return "lmb_dbl_click";
		case WE_RMB_DBL_CLICK:	return "rmb_dbl_click";
		case WE_RMB_CLICK:		return "rmb_click";
		case WE_LMB_RELEASE:	return "lmb_release";
		case WE_RMB_RELEASE:	return "rmb_release";
		case WE_LMB_REPEAT:		return "lmb_repeat";
		case WE_RMB_REPEAT:		return "rmb_repeat";
		case WE_CLIP_ENDED:		return "clip_ended";
		case WE_TEXT_ENTER:		return "text_enter";
		case WE_TEXT_SELECTED:	return "selected";
		case WE_TEXT_NEWINPUT:  return "text_input";
		case WE_UP_KEY:			return "up_key";
		case WE_DOWN_KEY:		return "down_key";
		case WE_LEFT_KEY:		return "left_key";
		case WE_RIGHT_KEY:		return "right_key";
		case WE_TAB_KEY:		return "tab_key";
		case WE_SLIDER_CHANGE:	return "slider_change";
		case WE_GRAPH_RISEN:	return "graph_risen";
		case WE_GRAPH_DROPPED:  return "graph_dropped";

	}
	return "unknown";
}

UIWidget::WIDGET_TYPE			UIWidget::GetType()
{
	return m_Type;
}

std::string			UIWidget::GetTypeName()
{
	return GetStringFromType(m_Type);
}


UIWidget::WIDGET_TYPE	UIWidget::GetTypeFromString(const std::string& Type)
{
	std::string	upr = Type;
    std::transform(upr.begin(), upr.end(), upr.begin(), tolower);

	if (upr == "widget") return WT_WIDGET;
	if (upr == "progress") return WT_PROGRESS;
	if (upr == "slider") return WT_SLIDER;
	if (upr == "verslider") return WT_VERSLIDER;
	if (upr == "dropdown") return WT_DROPDOWN;
	if (upr == "multiline") return WT_MULTILINE;
	if (upr == "checkbox") return WT_CHECKBOX;
	if (upr == "flash") return WT_FLASHWIDGET;
	if (upr == "partsys") return WT_PARTWIDGET;
	if (upr == "part2d") return WT_PART2DWIDGET;
	if (upr == "movie") return WT_MOVIEWIDGET;
	if (upr == "graph") return WT_GRAPH;
	if (upr == "polyline") return WT_POLYLINE;
	if (upr == "calendar") return WT_CALENDAR;
	if (upr == "flexeffect") return WT_FLEXEFFECT;
	if (upr == "list") return WT_LIST;
	if (upr == "biped") return WT_BIPED;
	if (upr == "drag") return WT_DRAG;
	return WT_WIDGET;
}


std::string	UIWidget::GetStringFromType(UIWidget::WIDGET_TYPE Type)
{
	switch (Type)
	{
		case WT_WIDGET:			return "widget";
		case WT_PROGRESS:		return "progress";
		case WT_SLIDER:			return "slider";
		case WT_VERSLIDER:		return "verslider";
		case WT_DROPDOWN:		return "dropdown";
		case WT_MULTILINE:		return "multiline";
		case WT_CHECKBOX:		return "checkbox";
		case WT_FLASHWIDGET:	return "flash";
		case WT_PARTWIDGET:		return "partsys";
		case WT_PART2DWIDGET:	return "part2d";
		case WT_MOVIEWIDGET:	return "movie";
		case WT_GRAPH:			return "graph";
		case WT_POLYLINE:		return "polyline";
		case WT_CALENDAR:       return "calendar";
		case WT_FLEXEFFECT:		return "flexeffect";
		case WT_LIST:			return "list";
		case WT_BIPED:			return "biped";
		case WT_DRAG:			return "drag";
	}
	return "widget";
}

UIWidget::WIDGET_IMAGE	UIWidget::GetImageStateFromText(const std::string& Text)
{
	std::string	upr = Text;
    std::transform(upr.begin(), upr.end(), upr.begin(), tolower);
	
	for (int i=0; i<WI_COUNT; i++)
	{
		WIDGET_IMAGE img = (WIDGET_IMAGE )i;
		if (GetImageTextFromState(img)==upr) return img;
	}
	return WI_MOUSE_OFF;
}

std::string	UIWidget::GetImageTextFromState(UIWidget::WIDGET_IMAGE wi)
{
	switch (wi)
	{
		case WI_MOUSE_OFF:		return "mouse_off";
		case WI_MOUSE_OVER:		return "mouse_over";
		case WI_MOUSE_CLICK:	return "mouse_click";
		case WI_FULL:			return "full";
		case WI_EMPTY:			return "empty";
		case WI_BUTTON:			return "button";
		case WI_BACKGROUND:		return "background";
		case WI_CHECKED:		return "checked";
		case WI_UNCHECKED:		return "unchecked";
	}
	return "mouse_off";
}

void				UIWidget::SetSkin(const std::string& Skin)
{
	UTIL_SAFE_DELETE(m_pSkin);
	if (Skin.empty()) return;
	m_pSkin = UISkin::Instance().CreateElement(Skin);
}

std::string			UIWidget::GetSkin()
{
	if (m_pSkin)
		return m_pSkin->Name;
	return "";
}

void				UIWidget::SetImage(WIDGET_STATE State, const std::string& Image)
{
	assert(State <WS_COUNT && "Illegal state!");
	m_ImageA[State].SetImage(Image);
	if (m_UseMask)
		m_ImageA[State].CreateMask();
}

void				UIWidget::SetImage(WIDGET_IMAGE State, const std::string& Image)
{
	assert(State <WI_COUNT && "Illegal state!");
	m_ImageA[State].SetImage(Image);
	if (m_UseMask)
		m_ImageA[State].CreateMask();
}

void				UIWidget::SetImage(WIDGET_STATE State, const char* ImageData, int DataSize)
{
	assert(State <WS_COUNT && "Illegal state!");
	m_ImageA[State].SetImage(ImageData, DataSize);
	if (m_UseMask)
		m_ImageA[State].CreateMask();
}

void				UIWidget::SetImage(WIDGET_IMAGE State, const char* ImageData, int DataSize)
{
	assert(State <WI_COUNT && "Illegal state!");
	m_ImageA[State].SetImage(ImageData, DataSize);
	if (m_UseMask)
		m_ImageA[State].CreateMask();
}




bool				UIWidget::IsInteractive() const
{
	for (int i=0; i<WE_COUNT; i++)
	{
		if (!m_EventA[i].empty()) return true;
	}	
	return false;
}

void				UIWidget::GetInteractiveWidgets(std::vector<UIWidget*>& List)
{
	if (IsInteractive())
	{
		List.push_back(this);
	}
	for (ElementList::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
			It->second->GetInteractiveWidgets(List);
	}
}

void UIWidget::SetOverMode(int aOverMode)
{
	m_OverMode = (WIDGET_OVER_MODE)aOverMode;
}

int UIWidget::GetOverMode() const 
{
	return m_OverMode;
}

void UIWidget::SetUseMask(bool b)
{
	if (b == m_UseMask) return;
	m_UseMask = b;

	for (int i = 0; i < WS_COUNT; i++)
	{
		if (!m_ImageA[i].IsValid()) continue;
		if (m_UseMask)
			m_ImageA[i].CreateMask();
	}

	OnMaskUpdated();
}

void	UIWidget::SetIsRenderRotated(bool b)
{
	m_IsRenderRotated = b;
}




void UIWidget::Register(LuaPlus::LuaState* _pScript)
{
#ifdef _ENABLE_LUABIND
	
	using namespace luabind;
	
    lua_State * L = _pScript->GetCState ( );
	
	luabind::module(L)
    [

		luabind::class_< UIWidget >( "Widget" )
		.def( "GetName",				&UIWidget::GetName) 
        .def( "GetType",				&UIWidget::GetTypeName) 
        .def( "SetPosition",			&UIWidget::SetPosition) 
        .def( "GetPosition",			&UIWidget::GetPosition, copy(result)	) 
		.def( "SetPositionRelativeToParent",			&UIWidget::SetPositionRelativeToParent)
        .def( "SetSize",				&UIWidget::SetSize) 
        .def( "GetSize",				&UIWidget::GetSize,		copy(result)	)  
        .def( "SetColor",				&UIWidget::SetColor) 
        .def( "GetColor",				&UIWidget::GetColor)   
        .def( "SetScale",				&UIWidget::SetScale) 
        .def( "GetScale",				&UIWidget::GetScale) 
        .def( "SetRotation",			&UIWidget::SetRotation) 
        .def( "GetRotation",			&UIWidget::GetRotation) 
        .def( "SetCanDrag",				&UIWidget::SetCanDrag) 
        .def( "GetCanDrag",				&UIWidget::GetCanDrag) 
        .def( "SetIsActive",			&UIWidget::SetIsActive) 
        .def( "GetIsActive",			&UIWidget::GetIsActive) 
        .def( "SetIsVisible",			&UIWidget::SetIsVisible) 
        .def( "GetIsVisible",			&UIWidget::GetIsVisible) 
        .def( "Tick",					&UIWidget::Tick) 
        .def( "SetFont",				&UIWidget::SetFont) 
        .def( "GetFont",				&UIWidget::GetFont)  
		.def( "SetText",				&UIWidget::SetTextA)		// note that LUA bind needs std::string, not wstring
		.def( "AppendText",				&UIWidget::AppendTextA)	// note that LUA bind needs std::string, not wstring
		.def( "TrimSpaces",				&UIWidget::TrimSpaces)
        .def( "GetText",				&UIWidget::GetTextA) 
        .def( "SetTextColor",			&UIWidget::SetTextColor) 
        .def( "GetTextColor",			&UIWidget::GetTextColor)
		.def( "SelectAllText",			&UIWidget::SelectAllText)
		.def( "SetCanEdit",				&UIWidget::SetCanEdit)
		.def( "GetCanEdit",				&UIWidget::GetCanEdit)

		.def( "DeleteChild",			&UIWidget::RemoveChild)
		.def( "RenameWidget",			&UIWidget::RenameWidget)
		.def( "GetParent",				&UIWidget::GetParent)
		.def( "GetWidgetByName",		&UIWidget::GetWidgetByName)

	 
		.def( "GetSliderByName",		&UIWidget::GetSliderByName)
		.def( "GetProgressByName",		&UIWidget::GetProgressByName)
		.def( "GetMultiLineByName",		&UIWidget::GetMultiLineByName)
		.def( "GetDropDownByName",		&UIWidget::GetDropDownByName)
		.def( "GetCheckBoxByName",		&UIWidget::GetCheckBoxByName)
#ifndef _PLATFORM_WII
		.def( "GetFlashWidgetByName",	&UIWidget::GetFlashWidgetByName)
#endif _PLATFORM_WII		
		.def( "GetPartWidgetByName",	&UIWidget::GetPartWidgetByName)
		.def( "GetMovieWidgetByName",	&UIWidget::GetMovieWidgetByName)
		.def( "GetListWidgetByName",	&UIWidget::GetListWidgetByName)
		.def( "GetBipedWidgetByName",	&UIWidget::GetBipedWidgetByName)
		.def( "GetDragWidgetByName",	&UIWidget::GetDragWidgetByName)
		
	 
        .def( "SetOffImage", 			&UIWidget::SetOffImage)
        .def( "SetOverImage", 			&UIWidget::SetOverImage)
        .def( "SetClickImage", 			&UIWidget::SetClickImage)
        .def( "SetAllImage", 			&UIWidget::SetAllImage)

		.def( "SetGainFocusEvent", 		&UIWidget::SetGainFocusEvent)
        .def( "SetLooseFocusEvent", 	&UIWidget::SetLooseFocusEvent)
        .def( "SetOnDragEvent", 		&UIWidget::SetOnDragEvent)
        .def( "SetOnDropEvent", 		&UIWidget::SetOnDropEvent)
        .def( "SetMouseOverEvent", 		&UIWidget::SetMouseOverEvent)
        .def( "SetMouseOffEvent", 		&UIWidget::SetMouseOffEvent)
        .def( "SetMouseHooverEvent", 	&UIWidget::SetMouseHooverEvent)
        .def( "SetClickLMBEvent", 		&UIWidget::SetClickLMBEvent)
        .def( "SetClickRMBEvent", 		&UIWidget::SetClickRMBEvent)
        .def( "SetRepeatLMBEvent", 		&UIWidget::SetRepeatLMBEvent)
        .def( "SetRepeatRMBEvent", 		&UIWidget::SetRepeatRMBEvent)
        .def( "SetDblClickLMBEvent", 	&UIWidget::SetDblClickLMBEvent)
        .def( "SetDblClickRMBEvent", 	&UIWidget::SetDblClickRMBEvent)
        .def( "SetReleaseLMBEvent", 	&UIWidget::SetReleaseLMBEvent)
        .def( "SetReleaseRMBEvent", 	&UIWidget::SetReleaseRMBEvent)
		.def( "SetClipEndedEvent",		&UIWidget::SetClipEndedEvent)
		.def( "SetTextEnterEvent",		&UIWidget::SetTextEnterEvent)
		.def( "SetTextSelectedEvent",	&UIWidget::SetTextSelectedEvent)
		.def( "ClearMovers",			&UIWidget::ClearMovers)
		.def( "DeleteMovers",			&UIWidget::DeleteMovers)
		.def( "FitToRect",				&UIWidget::FitToRect)		
		.def( "SetOverMode",			&UIWidget::SetOverMode)
		.def( "GetOverMode",			&UIWidget::GetOverMode)		
		.def( "SetBlockAllEvents",		&UIWidget::SetBlockAllEvents)		
		.def( "HasAnimation",			&UIWidget::HasAnimation)		
		
	];
#endif // _ENABLE_LUABIND
}

/// set an event delegate
bool UIWidget::SetEventDg(WIDGET_EVENT Event, const UIWidget::tdgEvent& adgEvent)
{
	assert(Event < WE_COUNT && Event >= 0 && "Illegal range for event!");
	m_EventDg[Event] = adgEvent;
	return true;
}

/// retrieve the event delegate
const UIWidget::tdgEvent&	UIWidget::GetEventDg(WIDGET_EVENT Event) const 
{
	assert(Event < WE_COUNT && Event >= 0 && "Illegal range for event!");
	return m_EventDg[Event];
}

